/*****************************************************************************
 * jQuery Finder v0.8 - Makes lists into a Finder, similar to Mac OS X
 * 
 * @date		$Date: 2009-06-16 09:45:10 +0000 (Tue, 16 Jun 2009) $
 * @revision 	$Rev: 22 $
 * @author		$Author: rudas.n $
 * @copy		(c) Copyright 2009 Nicolas Rudas. All Rights Reserved.
 * @licence		MIT Licensed
 * @discuss		groups.google.com/group/jquery-en/browse_thread/thread/480bb6f722b66345
 * @issues		code.google.com/p/jqueryfinder/issues/
 * @latest		code.google.com/p/jqueryfinder/source
 * @demo		nicolas.rudas.info/jquery/finder
 * 
 *****************************************************************************
 * Syntax:
 *		$(selector).finder()					Create a new finder with default options
 *
 *		$(selector).finder(options)				Create a new finder with additional options
 *
 *		$(selector).finder(method,[arguments])	Execute a method on an existing finder
 *												-	select			Select item
 *												-	refresh			Reload currently selected item (cache is ignored)
 *												-	destroy			Completely remove finder

 *												
 **/
;(function($){
	(function() {
		var f = function() {};
		(!window.console && (window.console = { log: f, warn:f, error:f, info: f, time:f, timeEnd: f, dir: f }));
	})();
$.fn.finder = function(o,m){
// Default options
	var defaults = {
		title: '',
		root_url: false,
		paging: false,
		animate: false,
		cache: false,
		ajax: {
			dataFilter: function(data,type) { return data; }
		}, 
		scrollTo: {	item: 500, column: 0 },
		max_column_width: 450,
		max_cycles: 1,
		list_item_node_type: 'li',
		list_item_parent_node_type: 'ol,ul',
		classNames: {
			'ui-finder' : 'ui-widget ui-widget-header',
			'ui-finder-wrapper' : 'ui-widget-content',
			'ui-finder-header' : undefined,
			'ui-finder-title' : undefined,
			'ui-finder-list-item-active' : 'ui-state-default',
			'ui-finder-list-item-activeNow' : 'ui-state-hover',
			'ui-finder-list-item-file' : 'ui-icon-document',
			'ui-finder-list-item-folder' : 'ui-icon-folder-collapsed',
			'ui-finder-icon-folder-arrow' : 'ui-icon ui-icon-triangle-1-e'
		},
		events: {
			root_ready: [],
			init_before: [],
			init_after: [ // after init, first thing to do is add click event for selecting items
				function(cycle){
				// Bind click events to wrapper so that only one event per finder is specified
				// Click event to handle showing of columns etc
					//container.bind('click.ui-finder-select',self.events['ui-finder-select']);
					var self = this;
					this.elements.container.bind('click.ui-finder-select',function(e) {
						var settings = self.settings,
							target = e.target,
							$target = $(target),
							target_list_item = $target.closest(settings.list_item_node_type+'.ui-finder-list-item');

						if( !target_list_item.length ) { return; }

						console.time('click');

						var action = (target.nodeName === 'A')
										? 'open'
										: 'select',
							cycle = self.cycle({
								method: 'select',
								action: action, // select, open, append
								event: e, // .target ..
								target_list_item: target_list_item,
								target_anchor_item: target_list_item.children('a:first'),
								target_container: target_list_item.parents(settings.list_item_parent_node_type+':first'),
								target_column: target_list_item.parents('div.ui-finder-column'),
								start: function(){
									this.target_list_item && this.target_list_item.addClass('ui-finder-loading');
								},
								end: function(){
									this.target_list_item && this.target_list_item.removeClass('ui-finder-loading');

								},
								abort: function(){
									this.target_list_item && this.target_list_item.removeClass('ui-finder-loading');


								},
								autoScroll: false
							});

						cycle.url = cycle.target_anchor_item.attr('href');

						console.timeEnd('click')

						var next = self.trigger('select',cycle);

						if ( next === false  ) { next = true; } // don't cycle, follow link
						else {	cycle.start();	next = false;	} 					

						return next;
					});
				}
			],
			retrieve_data_before: [],
			retrieve_data_after: [],
			process_data_before: [],
			process_data_after: [],
			display_data_before: [],
			display_data_after: [ // after displaying data (add column), bind scroll event
				function(cycle) {
					var self = this,
						column = cycle.data_target;

					column
						.unbind('scroll.ui-finder-scroll')
						.bind('scroll.ui-finder-scroll',function(e) {
							if(!self.settings.paging){return;}

							var $this = $(this),
								scrollTop = this.scrollTop, // how much did we scroll
								scrollHeight = this.scrollHeight, // how much is the scroll space
								offsetHeight =  this.offsetHeight, // how much is the height
								height_available = scrollHeight - offsetHeight; // how much scroll space available

					//		console.warn('SCROLL',e,this)

							if( height_available != scrollTop
								|| $this.data('finder-scroll-ignore')
								|| $this.data('finder-loading-next-page') ) {
									return; } 

					//		console.error(e);

							console.time('scroll');

							var cycle = self.cycle({
									method: 'scroll',
									cache: false,
									action: 'append', // select, open, append
									url: $this.attr('data-finder-list-source') ,
									event: e, // .target ..
									data_target: $this,
									start: function(){
										if( $this.css('position') != 'static' ) {
											$this.css('max-width',null);
										}

										$this.data('finder-loading-next-page',true);

									},
									end: function(){
										$this.data('finder-loading-next-page',false);
									}
								});

							console.timeEnd('scroll');

							cycle.start();

						});

				}
			],
			select: []
		}
	};
	
	
// Keep a reference to all finders created
	var Finders = $.Finders = $.Finders || {};
	
// Return a new timestamp
// Usually used for caching URLs, or creating unique identifiers e.g. Finders[ timestamp() ] = new Finder();
	var random_number = function() {
		return Math.floor(Math.random()* new Date().valueOf() );  };
	
// Internal debugging
	var debug = function(){
		var msg = ($.browser.mozilla)
					? arguments
					: $.makeArray(arguments).join(', ');

		if(typeof console == 'object') {
			console.log(msg);
		} else {
			$('body').prepend('<p>'+msg+'</p>');
		}
		
	};
	
	
// Check if scrollTo Plugin exists
	var scrollToPlugin = $.scrollTo || false;
	if(typeof scrollToPlugin == 'function') {
		scrollToPlugin = true;
		$.scrollTo.defaults.axis = 'xy';
	} 

// Set some variables (know what we are dealing with)
	var method, opts,
		url = (typeof m == 'string') ? m : null,
		func = (typeof m == 'function') ? m : null,
		_args = arguments;
		
	if(typeof o == 'string') { method = o; }
	else if (typeof o == 'object')  { opts = o; }
		
	if(opts) {
		if(opts.classNames) {
			opts.classNames = jQuery.extend(defaults.classNames, opts.classNames); }
		opts = jQuery.extend({},defaults, opts);}
	else { opts = defaults;}
	
	/**
	 * Finder Constructor
	 * 
	 *
	 **/
	function Finder(element){
		var self = this;
		
		element = $(element);
		
		this.id = random_number(); // something unique for each finder
		var settings = this.settings = $.extend({},defaults,opts),
			events = settings.events;
		
		this.events = $.extend({},defaults.events);
	
	// if provided events in options as callbacks, move them to events
	// (just making it easier to add events)
		(opts.root_ready && this.events.root_ready.push( opts.root_ready ) );
		(opts.retrieve_data	&& this.events.retrieve_data_before.push( opts.retrieve_data ) );
		(opts.process_data && this.events.process_data_before.push( opts.process_data ) );
		(opts.display_data && this.events.display_data_before.push( opts.display_data ) );
		(opts.select && this.events.select.push( opts.select ) );
		
		for(var e in events) {
			this.events[e] = this.events[e] || []
			this.events[e] = this.events[e].concat(events[e]); } 
		
		delete this.settings.events;
		delete this.settings.root_ready;
		delete this.settings.retrieve_data;
		delete this.settings.process_data;
		delete this.settings.display_data;
		delete this.settings.select;
				
		this.cache = {}; // stores received data
		this.current_queue = []; // stuff to do
		this.current_container_width = 0; // changes as more columns are added
		this.isProcessing = false; // true if waiting for ajax responses or working with existing data
		this.widget_width = 0;

		this.elements = {
			original: element, // Reference to initial element - used when destroying Finder
			widget: null, // everything is in here (.ui-finder)
			title: null, // .ui-finder-title
			header: null, // .ui-finder-header
			wrapper: null, // wraps container (.ui-finder-wrapper), allows for scrolling
			container: null // columns are in here (.ui-finder-container)
		};
				
		this.methods = {
			'select': function(cycle) {
				console.time('select')
				
			//	console.time('select: vars')
				var self = this,
					elements = self.elements,
					settings = self.settings,
					wrapper = elements.wrapper,
					container = elements.container,
					list_item_node_type = settings.list_item_node_type,
					list_item_parent_node_type = settings.list_item_parent_node_type,

					scrollTo_item_duration = settings.scrollTo.item || 0,

					classes = settings.classNames,
					classes_active = classes['ui-finder-list-item-active'] || '',
					classes_active_now = classes['ui-finder-list-item-activeNow'] || '',
					columns = $('div.ui-finder-column:not(.ui-finder-hidden-column)',container);
					
				var	target_list_item = cycle.target_list_item,
					target_anchor_item = cycle.target_anchor_item,
					target_column = cycle.target_column,
					target_column_depth_level = target_column && target_column.attr('data-finder-list-level'),
					target_container = cycle.target_container;
				
				if(target_column && target_column.is('.ui-finder-hidden-column')) {
				// selecting different items at multiple levels can break the finder
				// if the target element of this cycle is not visible then
				// ignore this cycle
					cycle.end();
					return;
				}
				
				console.error(cycle.url)
				
				if(!cycle.url){ // not triggered by a click event (thru api?)
					var event_target = cycle.event.target,
						$target;
						
					if(typeof event_target === 'number') {// find by index
						$target = $(list_item_node_type+'.ui-finder-list-item',columns).eq( event_target ); }
					
					else if( typeof event_target === 'string') {// find by href
						$target = $('a[href="'+event_target+'"]',columns).eq(0); }
					
					
					cycle.target_list_item = target_list_item = $target.closest(list_item_node_type+'.ui-finder-list-item');
				
					cycle.target_anchor_item = target_anchor_item = target_list_item.children('a:first');
					
					cycle.target_container = target_container = target_list_item.parents(list_item_parent_node_type+':first');
					
					cycle.target_column = target_column = target_list_item.parents('div.ui-finder-column');
					
					cycle.url = target_anchor_item.attr('href');
					
					target_column_depth_level = target_column && target_column.attr('data-finder-list-level');
				}	
				
				
				if(cycle.url === 'root') { // retrieve root
					cycle.url = this.settings.root_url || false;	} 
				
				if(!cycle.url) {cycle.abort();	return this;	}
							
				if(target_column) {
			//		console.time('select: change classes')
				// Currently selected item will no longer be active
					$(list_item_node_type+'.ui-finder-list-item-activeNow',container)
						.removeClass('ui-finder-list-item-activeNow ' + classes_active_now  );	
				// Neither will active items in the same column as the current one
					$(list_item_node_type+'.ui-finder-list-item-active',target_column)
						.removeClass('ui-finder-list-item-active ' + classes_active  );	
			//		console.timeEnd('select: change classes')
							
			//		console.time('select: loop columns')
					columns.each(function(){
						var column = $(this),
							column_depth_level = column.attr('data-finder-list-level');

					//	column[0].style.width = column.data('finder-width') + 'px'
						this.style.position = 'static';
						
						column.css('max-width', column.data('finder-width') )
						
						if( column_depth_level > target_column_depth_level ) {
							$(list_item_node_type+'.ui-finder-list-item-active',column)
								.removeClass('ui-finder-list-item-active ' + classes_active ); 

							self.current_container_width -= column.data('finder-width');
							column.addClass('ui-finder-hidden-column');
						}
					});			
			//		console.timeEnd('select: loop columns')
			//		console.time('select: add classes')
				// Style selected list item
					target_list_item
						.addClass('	ui-finder-loading\
									ui-finder-list-item-active\
									ui-finder-list-item-activeNow '+ classes_active+' '+classes_active_now);				
			//		console.timeEnd('select: add classes')
			
					self.fix_width(cycle);
					
				// Scroll to selected item
				// Mostly useful if item not selected following direct user action (e.g. click event) 
					scrollToPlugin && cycle.autoScroll
						&& target_column.data('finder-scroll-ignore',true)
						&& target_column.scrollTo(target_list_item,{
							duration: scrollTo_item_duration,
							onAfter: function() {
								target_column.data('finder-scroll-ignore',false);
							}
						});
							
				
				}

				console.timeEnd('select')
				
				self.retrieve_data(cycle);
				
				return this;
			},
			'scroll': function(cycle) {
				self.retrieve_data(cycle);
			}
		}
		
		this.method = function(name) {
			return this.methods[name] && this.methods[name].apply(this,Array.prototype.slice.call(arguments,1))
		};
	
		return this;
	};

	/**
	 * Initialise Finder
	 * Append necessary HTML, bind events etc
	 *
	 **/
	Finder.prototype.init = function(){
		console.time('init')
		var self = this,
			settings = self.settings,
			settings_classes = settings.classNames,
			class_ui_finder = settings_classes['ui-finder'] || '',
			class_ui_finder_wrapper = settings_classes['ui-finder-wrapper'] || '',
			class_ui_finder_header = settings_classes['ui-finder-header'] || '',
			class_ui_finder_title = settings_classes['ui-finder-title'] || '',
			elements = this.elements;
			

		var widget = elements.widget = (function() {
			var finder_dom = '\
				<div class="ui-finder '+class_ui_finder+'">\
					<div class="ui-finder-title '+class_ui_finder_title+'"></div>\
					<div class="ui-finder-header '+class_ui_finder_header+'"></div>\
					<div class="ui-finder-wrapper '+class_ui_finder_wrapper+'" id="'+self.id+'">\
						<div class="ui-finder-container">\
							'+elements.original[0].innerHTML+'\
						</div>\
					</div>\
				</div>\
			';
			return $(finder_dom);
		})(),
			wrapper = elements.wrapper = $('div.ui-finder-wrapper',widget),
			container =	elements.container = $('div.ui-finder-container',widget),
			original = elements.original;
				
		original
			.after(widget)
			.hide();
			
		elements.title = $('div.ui-finder-title',widget);
		elements.header = $('div.ui-finder-header',widget);
		
		
		this.widget_width = widget.width();
				
		$(window).bind('resize.ui-finder',function() {
			self.widget_width = widget.width();
		});			
				
		console.timeEnd('init')	;
				
		self.method('select',self.cycle({
			action: 'open', // select, open, append
			url: 'root', // fetch data from
			end: function(){
				var cycle = this;
				setTimeout(function() {
					self.trigger('root_ready',cycle);
				}, 0);
			}
		}));
		
		
		this.trigger('init_after');
		
		return this;
	};

	Finder.prototype.addToQueue = function(cycle) {
		var self = this;
		
		this.current_queue.push( cycle );

	// isProcessing is set to true when the Finder is currently 'doing stuff'
	// and set to false when not. So, if its not doing anything right now,
	// continue to process this event
		if(!this.isProcessing && this.current_queue.length === 1) {
			this.isProcessing = true;
			var cycle = this.current_queue.shift();

			cycle.__custom_start && cycle.__custom_start();

			cycle.method && self.method(cycle.method,cycle);
			
		}

		return this;
	};
	Finder.prototype.moveQueue = function() {
		var self = this,
			q = this.current_queue;
		
	//	self.isProcessing = false;
		this.isProcessing = false;
		
		if(q.length === 0) {
			return this; }
		
	//	self.isProcessing = true;
		
		
		var cycle = this.current_queue.shift();
		
		cycle.__custom_start && cycle.__custom_start();
		
		cycle.method && self.method(cycle.method,cycle);
		
		return this;
	};

	Finder.prototype.retrieve_data = function(cycle) {
		if(this.trigger('retrieve_data_before',cycle) === false) {
			console.warn('retrieve_data: abort cycle',cycle)
			return this;
		}
		
		var self = this,
			settings = self.settings,
			ajax_settings = settings.ajax,
			cache = self.cache,
			use_cache = cycle.cache,
			process_data = cycle.process_data,
			retrieved_data;
		
		retrieved_data = use_cache && cache[cycle.url]; // get from cache
		retrieved_data = retrieved_data || (cycle.target_list_item // get from dom
							&& cycle.target_list_item.children(settings.list_item_parent_node_type).eq(0).clone());
		
		if( !retrieved_data || (retrieved_data.jquery && !retrieved_data.length) ) {
		
			ajax_settings = $.extend({},ajax_settings,{
				url: cycle.url,
				success: function(response){
					cont(response);
				}
			});
			
			cycle.XMLHttpRequest = $.ajax(ajax_settings);
			
		} else {
			cont(retrieved_data)
		}
		
		function cont(response){
			cycle.data_response = response;
		// does not update cache (scrolling?)
			cache[cycle.url] = cache[cycle.url] || cycle.data_response;
			
			if(self.trigger('retrieve_data_after',cycle) === false) {
				console.warn('retrieve_data_after: abort cycle',cycle)
				return;
			}			
			process_data && self.process_data(cycle);
			!process_data && cycle.end();
		}
	

		return this;
	};
	
	Finder.prototype.process_data = function(cycle) {
		if(this.trigger('process_data_before',cycle) === false) {
			console.warn('process_data: abort cycle',cycle)
			return this;
		}
					
		var self = this,
			settings = self.settings,
			
			display_data = cycle.display_data,
			
			list_item_node_type = settings.list_item_node_type,
			list_item_parent_node_type = settings.list_item_parent_node_type;
		
		var data_response = cycle.data_processed; 

		if (!data_response) {
			throw new Error('jQuery Finder: no data response',''); }
		
		console.time('process_data')
	
		data_response = (!data_response.jquery) ? $(data_response) : data_response;

		var list_items = data_response.children(list_item_parent_node_type).eq(0).children(list_item_node_type);

	// Process data. Find list items and add necessary classes and icons
		list_items.each(function(i){ //
			var $this = $(this),
				className = this.className,
				classNameTypeMatch = className.match(/ui\-finder\-(file|folder)/),
				thisType,thisTypeClass;

		// Get the type of this list item (file or folder)
			if(classNameTypeMatch && classNameTypeMatch[1]) {
				thisType = classNameTypeMatch[1]; }

		// If type (file or folder) is not specified try to figure it out
			else {
				if($this.children(list_item_parent_node_type).length) {
					this.className += ' ui-finder-folder';
					thisType = 'folder'; }
				else { // default type is file
					this.className += ' ui-finder-file';
					thisType = 'file';  } }

			thisTypeClass = settings.classNames['ui-finder-list-item-'+thisType];

			var span = document.createElement('span');
			span.className = settings.classNames['ui-finder-icon-folder-arrow'] + ' \
							ui-finder-icon ui-finder-icon-arrow';
			this.appendChild(span);
			this.className += ' ui-finder-list-item';

		// Process links
			var anch = $this.children('a:first'),
				anchHref = anch.attr('href') || '_blank'+ random_number(),
				anchTitle = anch.attr('title') || '';

			if( !anch.length ){ // not necessary to have a link
				return; }

			anch.attr('href',anchHref);

			span = document.createElement('span');
			span.className = 'ui-icon '+thisTypeClass+' ui-finder-icon ui-finder-icon-'+thisType;
			anch[0].appendChild(span);

			if(anchTitle.length == 0) {anch.attr('title',anchHref);}	
		});
		
		console.timeEnd('process_data')
		
		cycle.data_processed = data_response;
		
		if(this.trigger('process_data_after',cycle) === false) {
			console.warn('process_data_after: abort cycle',cycle)
			return this;
		}
		
		display_data && self.display_data(cycle);
		
		!display_data && cycle.end();
		
		return this;
	};
	
	Finder.prototype.display_data = function(cycle) {
		if(this.trigger('display_data_before',cycle) === false) {
			console.warn('display_data_before: abort cycle',cycle)
			return this;
		}
			
		console.time('display_data')
		var self = this,
			settings = self.settings,
			elements = self.elements,
			wrapper = elements.wrapper,
			container = elements.container,
			data = cycle.data_processed,
			column, column_width;
		
		if(cycle.data_target) { // column exists
			console.error('COLUMN EXISTS')
			column = cycle.data_target.removeClass('ui-finder-hidden-column');
		}		
			
		else {
			var column_id = cycle.url.replace(/[\W\s]*/g,'') + random_number(),
				column_depth_level = (function(){
					return (cycle.target_column && parseInt(cycle.target_column.attr('data-finder-list-level'),10) + 1)
							|| 0;
				})();
				
			column = document.createElement('div');
			
			column.id = column_id;
			column.setAttribute('data-finder-list-source',cycle.url);
			column.setAttribute('data-finder-list-level',column_depth_level);
			column.className = 'ui-finder-column ui-widget-content';
			column.style.display = 'none';
	
			container[0].appendChild(column);

			column.appendChild(data[0]);
			
			column = cycle.data_target = $(column);
		
			column.data('finder-width',column.width())
		
		}
		
		
		if(this.trigger('display_data_after',cycle) === false) {
			console.warn('display_data_after: abort cycle',cycle)
			return this;
		}
		
		console.timeEnd('display_data')
		this.current_container_width += column.data('finder-width');
		
		self.fix_width(cycle);
		
		cycle.end();
		
		return this;
	};
		
	Finder.prototype.fix_width = function(cycle) {
		console.time('fix_width');
		
		var self = this,
			elements = self.elements,
			widget = elements.widget,
			wrapper = elements.wrapper,
			container = elements.container,
			settings = self.settings,
			
			total_column_width = this.current_container_width,
			total_available_width = this.widget_width,
			
			fix_column = cycle.data_target || cycle.target_column,
			
			fix_column_left = fix_column.data('finder-width'),
			
			scroll_to_column = false,
			scroll_to_column_duration = settings.scrollTo.column,
			
			__a;
		
		cycle.target_column && (cycle.target_column[0].style.position = 'static');
		
		
		if(total_column_width > total_available_width) {
			container.width(total_column_width);
			scroll_to_column = scrollToPlugin; }
		
		else {
			container.width( 'auto' ); }
		
		if(!fix_column || !fix_column.length) {
			console.error("NO LAST COLUMN WTF!?");
			return this; }
			
	// fix_column is about to change its width. 
	// This may cause the column to scroll and trigger the scroll event,
	// which we don't want
		fix_column.data('finder-scroll-ignore',true);
		
		fix_column = fix_column[0];
		fix_column.style.position = 'absolute';
		fix_column.style.right = '0px';
		fix_column.style.left = total_column_width - fix_column_left + 'px';
		fix_column.style.display = 'block';
		fix_column.style.height = '100%';
	
	// Its ok now for the column to scroll
		$(fix_column).data('finder-scroll-ignore',false);

		console.timeEnd('fix_width');
		
		scroll_to_column
			&& wrapper.scrollTo(fix_column,{ duration: scroll_to_column_duration || 0 });
		
		return this;
	};
	
	Finder.prototype.trigger = function(name,cycle) {
		var events = this.events,
			callbacks = events[name],
			//params = Array.prototype.slice.call(arguments,1),
			ret;
			
		if(!callbacks || !callbacks.length){ return this; }

		callbacks.reverse();
		
		for (var i = callbacks.length - 1; i >= 0; i--){
			var callback = callbacks[i],
				ret = callback.call(this,cycle);
				if(ret === false) {
					return cycle.end();
//					return false;
				}
		};
		
		
		return this;
	};
		
	Finder.prototype.cycle = function(opts) {
		var self = this;
	
		return (function() {
			var finder = self,
				start_fn = opts.start || function() {},
				end_fn = opts.end || function() {},
				abort_fn = opts.abort || function() {};
			delete opts.start;
			delete opts.end;
			delete opts.abort;
			var cycle = $.extend({
				id:random_number(),				
				method: null,
				cache: self.settings.cache,
				autoScroll: true,
				action: null, // select, open, append
				event: null, // .target ..
				target_list_item: null,
				target_anchor_item: null,
				target_container: null,
				target_column: null,
				url: null, // fetch data from
				XMLHttpRequest: null,
				data_response: null, // server response
				data_processed: null, // data to show
				data_target: null, // where the data will be shown
				process_data: true,
				display_data: true,
				__custom_start: start_fn,
				__custom_end: end_fn,
				__custom_abort: abort_fn,
				
				abort: function() {
					console.error('abort cycle',this);
					
					this.XMLHttpRequest && this.XMLHttpRequest.abort();
					this.__custom_abort();
					
					this.data_target && this.data_target.remove();
					
					this.process_data = false;
					this.retrieve_data = false;
					this.display_data = false;
					
					this.aborted = true;
					
					return false;
				},
				
				
				start: function() {
					finder.addToQueue(this);
				},
				end: function(){	
					this.__custom_end();
					finder.moveQueue();
					return false;
				}
			},opts);
			return cycle;
		})();
	};
	
	
	Finder.prototype._API_select = function(select_these,action) {
		var self = this,
			container = self.elements.container,
			list_item_node_type = self.settings.list_item_node_type,
			list_item_node_type = self.settings.list_item_node_type,
			columns = $('div.ui-finder-column:not(.ui-finder-hidden-column)',container);
			
		select_these = $.makeArray(select_these);
		
		$.each(select_these,function(i,which) {			
			var cycle =  self.cycle({
				method: 'select',
				action: action,
				event: {
					target: which
				},
				start: function(){
					this.target_list_item && this.target_list_item.addClass('ui-finder-loading');
				},
				end: function(){
					this.target_list_item && this.target_list_item.removeClass('ui-finder-loading');
				},
				abort: function(){
					this.target_list_item && this.target_list_item.removeClass('ui-finder-loading');
					
				},
				autoScroll: true
			}).start();
			
		/*	var next = self.trigger('select',cycle);

			if ( next === false  ) { next = true; } // don't cycle, follow link
			else {	cycle.start();	next = false;	} 					

			return next;*/
		});
		
	};

	Finder.prototype.title = function(val) {
		this.elements.title.html(val);
		return this;
	};
	
	Finder.prototype.header = function(val) {
		this.elements.header.html(val);
		return this;
	};
	
	Finder.prototype.destroy = function(){
		var self = this,
			elements = this.elements,
			original = elements.original,
			widget = elements.widget;
					
		widget.remove();
		
		original.show();
		
	// Delete reference to Finder
		delete Finders[this.id];
		
		return this;
	};
	
	Finder.prototype.current = function(){
		var current = $('.ui-state-hover',this.wrapper).find('a:first');
		return (current.length>0) ? current : null;
	};

	Finder.prototype.refresh = function(){
		var current = this.current();
		
		if(current) { this.queue(current,true); }
		else { this.selectItem('root',true); }
		
		return this;
	};
	
	var _finder = Finders[ $(this).eq(0).data('ui-finder-id') ];
	
	if(method === 'current' && _finder) { return _finder.current();	}
	else if(method === 'get' && _finder) { return _finder; }
	
	return this.each(function(){
		var finderId = $(this).data('ui-finder-id') || null;
			
	// If name of method provided
	// execute method
		if(finderId && method) {
			var finder = Finders[finderId];
			
		// Access private methods	
			if(m && method == 'select' || method === 'open') {
				finder._API_select(m,method);
			}
			else if(method == 'title') {	finder.title(m);	}
			else if(method == 'toolbar') {	finder.toolbar(m);	}
			else if(method == 'destroy') {	finder.destroy();	}
			else if(method == 'refresh') {	finder.refresh();	}
		}
	// If no method provided new finder is created
		else if (!method) {
			var new_finder = new Finder(this).init();
			Finders[new_finder.id] = new_finder;
			$(this).data('ui-finder-id',new_finder.id);
		} 
		else if (!finderId && method) {	throw 'jQuery Finder: Element is not a finder';	}
	});
};})(jQuery);